package com.ruoyi.merchant.utils;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

@Component
public class RedisGeoUtils {
    private final RedisTemplate<Object, Object> redisTemplate;

    public RedisGeoUtils(RedisTemplate<Object, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 添加地理位置
     * @param key Redis key
     * @param point 经纬度
     * @param member 成员标识
     */
    public void add(String key, Point point, Object member) {
        redisTemplate.opsForGeo().add(key, point, member);
    }

    /**
     * 批量添加地理位置
     * @param key Redis key
     * @param points 成员-坐标映射表
     */
    public void batchAdd(String key, Map<Object, Point> points) {
        points.forEach((member, point) ->
                redisTemplate.opsForGeo().add(key, point, member));
    }

    /**
     * 获取成员的地理位置
     * @param key Redis key
     * @param members 成员标识
     * @return 经纬度列表
     */
    public List<Point> getPositions(String key, Object... members) {
        return redisTemplate.opsForGeo().position(key, members);
    }

    /**
     * 计算两个成员间的距离
     * @param key Redis key
     * @param member1 成员1
     * @param member2 成员2
     * @param metric 距离单位 (默认米)
     * @return 距离值（带单位）
     */
    public Distance getDistance(String key,
                                Object member1,
                                Object member2,
                                Metric metric) {
        metric = (metric == null) ? Metrics.KILOMETERS : metric;
        return redisTemplate.opsForGeo()
                .distance(key, member1, member2, metric);
    }

    /**
     * 查询指定半径内的成员
     * @param key Redis key
     * @param center 中心点
     * @param radius 半径
     * @param metric 距离单位 (默认千米)
     * @param limit 返回结果数量限制
     * @return 附近成员列表（带距离）
     */
    public List<GeoResult<RedisGeoCommands.GeoLocation<Object>>> getNearbyMembers(
            String key,
            Point center,
            double radius,
            Metric metric,
            Integer limit) {

        metric = (metric == null) ? Metrics.KILOMETERS : metric;
        Circle circle = new Circle(center, new Distance(radius, metric));

        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands
                .GeoRadiusCommandArgs
                .newGeoRadiusArgs()
                .includeDistance()
                .includeCoordinates();

        if (limit != null) {
            args.limit(limit);
        }

        return redisTemplate.opsForGeo()
                .radius(key, circle, args)
                .getContent();
    }

    /**
     * 查询指定成员附近的成员
     * @param key Redis key
     * @param member 中心成员
     * @param radius 半径
     * @param metric 距离单位
     * @param limit 返回结果数量限制
     * @return 附近成员列表（带距离）
     */
    public List<GeoResult<RedisGeoCommands.GeoLocation<Object>>> getNearbyMembers(
            String key,
            Object member,
            double radius,
            Metric metric,
            Integer limit) {

        metric = (metric == null) ? Metrics.KILOMETERS : metric;
        Distance distance = new Distance(radius, metric);

        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands
                .GeoRadiusCommandArgs
                .newGeoRadiusArgs()
                .includeDistance()
                .includeCoordinates();

        if (limit != null) {
            args.limit(limit);
        }

        return redisTemplate.opsForGeo()
                .radius(key, member, distance, args)
                .getContent();
    }

    /**
     * 删除地理位置成员
     * @param key Redis key
     * @param members 待删除成员
     * @return 删除成员数量
     */
    public Long removeMembers(String key, Object... members) {
        return redisTemplate.opsForZSet().remove(key, members);
    }
}